<script lang="ts" setup>
import { useRoute } from 'vue-router'

import dayjs from 'dayjs'
import { type TableColumnsType, type TablePaginationConfig, message } from 'ant-design-vue'
import { computed, onMounted, reactive, ref } from 'vue'
import type { SorterResult } from 'ant-design-vue/es/table/interface'
import { storeToRefs } from 'pinia'
import { useI18n } from 'vue-i18n'
import { orderMap } from '../config'
import CveTask from './CveTask.vue'
import type { CveItemWithRpms, HostsInCve } from './CveTask.vue'
import TaskModal from './TaskModal.vue'
import CreateTaskDrawer from './CreateTaskDrawer.vue'
import { useClusterStore, useRepoStore } from '@/store'
import { api } from '@/api'
import type { AffectedHost, Direction, Rpm } from '@/api'

const { t } = useI18n()

const TaskNameEnum = computed(() => ({
  'cve fix': t('vul.cveFixTask'),
  'hotpatch remove': t('vul.hotPatchRemove'),
}))

const { repos } = storeToRefs(useRepoStore())
const { permissions } = storeToRefs(useClusterStore())

const route = useRoute()
const cveId = ref<string>('')
const isCveFixed = ref(false)
const cveList = computed<Array<CveItemWithRpms>>(() => {
  return [
    {
      cve_id: cveId.value,
      rpms: [],
    },
  ]
})
const tableState = reactive<{
  selectedRowKeys: string[]
  expandSelectedRowKeys: string[]
  loading: boolean
  expandedRowKeys: string[]
  isDrawerVisible: boolean
  isSuccessModalVisible: boolean
  countdown: number
  getCheckboxProps: any
}>({
  selectedRowKeys: [],
  expandSelectedRowKeys: [],
  loading: false,
  expandedRowKeys: [],
  isDrawerVisible: false,
  countdown: 0,
  isSuccessModalVisible: false,
  getCheckboxProps: () => {
    return {
      disabled: isCveFixed.value,
    }
  },
})
const hostTableData = ref<AffectedHost[]>([])

const hostListInCve = computed<HostsInCve[]>(() => {
  const list = hostTableData.value?.filter(host => tableState.selectedRowKeys.includes(host.host_id))

  return list.length === 0
    ? []
    : [
        {
          cve_id: cveId.value,
          hosts: list.map(({ host_id, host_ip, host_name, cluster_id, cluster_name }) => ({
            host_id,
            host_ip,
            host_name,
            cluster_id,
            cluster_name,
          })),
        },
      ]
})
function handleAffectChange() {
  tableState.expandedRowKeys = []
  tableState.selectedRowKeys = []
  tableState.expandSelectedRowKeys = []
  queryHosts()
}

const hostTableColumns = computed<TableColumnsType>(() => [
  { dataIndex: 'host_name', title: t('vul.hostName') },
  { dataIndex: 'host_ip', title: t('vul.ip') },
  {
    dataIndex: 'cluster_name',
    title: t('vul.cluster'),
    filters: permissions.value?.map(({ cluster_id, cluster_name }) => ({
      text: cluster_name,
      value: cluster_id,
    })),
  },
  {
    dataIndex: 'host_group_name',
    title: t('vul.hostGroup'),
    filters: permissions.value?.map(({ cluster_id, cluster_name, host_groups }) => ({
      text: cluster_name,
      value: cluster_id,
      children: host_groups.map(h => ({ text: h.host_group_name, value: h.host_group_id })),
    })),
    filterMode: 'tree',
    filterSearch: true,
  },
  {
    dataIndex: 'repo',
    title: 'CVE REPO',
    filters: repos.value?.map(i => ({ text: i.repo_name, value: i.repo_id })),
  },
  { dataIndex: 'last_scan', title: t('vul.lastScan'), sorter: true },
])

const pagination = reactive({
  total: 0,
  current: 1,
  pageSize: 10,
  showTotal: (total: number) => t('common.total', { count: total }),
  showSizeChanger: true,
  pageSizeOptions: ['10', '20', '30', '40'],
})

const hostExpandTableColumns = computed(() =>
  !isCveFixed.value
    ? [
        {
          key: 'available_rpm',
          dataIndex: 'available_rpm',
          title: t('vul.cveDetail.unfixed.rpms.availableRpm'),
        },
        {
          key: 'installed_rpm',
          dataIndex: 'installed_rpm',
          title: t('vul.cveDetail.unfixed.rpms.installedRpm'),
        },
        {
          key: 'support_way',
          dataIndex: 'support_way',
          title: t('vul.cveDetail.fixWay'),
        },
        {
          key: 'host_num',
          dataIndex: 'host_num',
          title: t('vul.cveDetail.hostNum'),
        },
      ]
    : [
        {
          key: 'installed_rpm',
          dataIndex: 'installed_rpm',
          title: t('vul.cveDetail.fixed.rpms.installedRpm'),
        },
        {
          key: 'fixed_way',
          dataIndex: 'fixed_way',
          title: t('vul.cveDetail.fixWay'),
        },
        {
          key: 'host_num',
          dataIndex: 'host_num',
          title: t('vul.cveDetail.hostNum'),
        },
      ],
)

async function handleExpand(expanded: boolean, record: AffectedHost) {
  if (!expanded)
    return
  await queryHostRpm(cveId.value, record.host_id)
  if (tableState.selectedRowKeys.includes(record.host_id))
    record.rpms && selectAllExpandRow(record.host_id, record.rpms)
}

const searchKey = ref()

function handleTableChange(page: TablePaginationConfig, filters: Record<string, string[] | null>, sorter: SorterResult<any>) {
  page.current && (pagination.current = page.current)
  page.pageSize && (pagination.pageSize = page.pageSize)

  const params = {
    sort: sorter.column ? (sorter.columnKey as string) : undefined,
    order: sorter.order ? orderMap[sorter.order] : undefined,
    clusterIds: filters.cluster_name ? filters.cluster_name : undefined,
    hostGroups: filters.host_group_name ? filters.host_group_name : undefined,
    repo: filters.repo ? filters.repo : undefined,
  }
  queryHosts(
    searchKey.value,
    params.sort,
    params.order,
    params.clusterIds,
    params.hostGroups,
    params.repo,
  )
}
/**
 * query host list by cve id
 * @param searchKey
 * @param sort
 * @param order
 * @param clusterIds
 * @param hostGroups
 * @param repos
 */
async function queryHosts(searchKey?: string, sort?: string, order?: Direction, clusterIds?: string[], hostGroups?: string[], repos?: string[]) {
  tableState.loading = true
  tableState.selectedRowKeys = []
  tableState.expandSelectedRowKeys = []
  tableState.expandedRowKeys = []
  const [, res] = await api.getHostsByCveId({
    cve_id: cveId.value,
    filter: {
      fixed: isCveFixed.value,
      host_name: searchKey || undefined,
      cluster_list: clusterIds,
      host_group_ids: hostGroups,
      repo: repos,
    },
    page: pagination.current,
    per_page: pagination.pageSize,
    sort,
    direction: order,
  })
  if (res) {
    hostTableData.value = res.result
    pagination.total = res.total_count
  }
  tableState.loading = false
}

async function queryHostRpm(cveId: string, hostId: string) {
  if (!isCveFixed.value) {
    const [, res] = await api.getUnfixedRpm({ cve_id: cveId, host_ids: [hostId] })

    if (res && hostTableData.value) {
      const host = hostTableData.value.find(item => item.host_id === hostId)
      if (!host)
        return
      host.rpms = res
    }
  }
  else {
    const [, res] = await api.getFixedRpm({ cve_id: cveId, host_ids: [hostId] })

    if (res && hostTableData.value) {
      const host = hostTableData.value.find(item => item.host_id === hostId)
      if (!host)
        return
      host.rpms = res
    }
  }
}
/**
 * select one of hosts
 */
function onSelect(record: AffectedHost, selected: boolean) {
  if (selected) {
    tableState.selectedRowKeys.push(record.host_id)
    record.rpms && selectAllExpandRow(record.host_id, record.rpms)
  }
  else {
    tableState.selectedRowKeys = tableState.selectedRowKeys.filter(
      item => item !== record.host_id,
    )
    record.rpms && cancelAllExpandRow(record.host_id, record.rpms)
  }
}
/**
 * select all host
 */
function onSelectAll(selected: boolean, selectedRows: AffectedHost[]) {
  if (!selected) {
    tableState.selectedRowKeys = []
    tableState.expandSelectedRowKeys = []
  }
  else {
    tableState.selectedRowKeys = selectedRows.map((item) => {
      if (item.rpms)
        selectAllExpandRow(item.host_id, item.rpms)

      return item.host_id
    },
    )
  }
}

function onExpandSelectedChange(selectedRowKeys: string[]) {
  const list = selectedRowKeys.map(item => item.split('&')[0])
  tableState.expandSelectedRowKeys = selectedRowKeys
  tableState.selectedRowKeys = list
}

function selectAllExpandRow(hostId: string, rpms: Rpm[]) {
  rpms.forEach((item) => {
    const key = `${hostId}&${item.installed_rpm}-${item.available_rpm}`
    tableState.expandSelectedRowKeys.push(key)
  })
}

function cancelAllExpandRow(hostId: string, rpms: Rpm[]) {
  rpms.forEach((item) => {
    const key = `${hostId}&${item.installed_rpm}-${item.available_rpm}`
    tableState.expandSelectedRowKeys = tableState.expandSelectedRowKeys.filter(
      item => item !== key,
    )
  })
}

// #region ----------------------------------------< task >----------------------------------------
const taskTypeMap = computed(() => ({
  'hotpatch remove': t('vul.hotPatchRemove'),
  'cve fix': t('vul.generateFixTask'),
}))

const taskType = computed(() => (isCveFixed.value ? 'hotpatch remove' : 'cve fix'))

function handleSearch() {
  queryHosts(searchKey.value)
}

function handleDrawerTrigger() {
  if (hostTableData.value.length === 0)
    return message.info(`${t('vul.cves.message.atLeastOne', { type: taskType.value === 'cve fix' ? t('vul.fix') : t('vul.remove') })}`)

  tableState.isDrawerVisible = true
}

// #endregion

onMounted(() => {
  cveId.value = (route.params.cve_id as string) ?? undefined
  queryHosts()
})
</script>

<template>
  <div>
    <a-row type="flex" justify="space-between">
      <a-col>
        <a-space>
          <a-radio-group
            v-model:value="isCveFixed"
            default-value="a"
            button-style="solid"
            @change="handleAffectChange"
          >
            <a-radio-button :value="false">
              {{ t('vul.unfixed') }}
            </a-radio-button>
            <a-radio-button :value="true">
              {{ t('vul.fixed') }}
            </a-radio-button>
          </a-radio-group>
          <a-input-search
            v-model:value="searchKey"
            :maxlength="40"
            :placeholder="t('vul.cveDetail.palceHolder.searchBy')"
            @search="handleSearch"
          />
        </a-space>
      </a-col>
      <a-col>
        <CreateTaskDrawer
          :title="taskTypeMap[taskType]"
          :visible="tableState.isDrawerVisible"
          @close="tableState.isDrawerVisible = false"
        >
          <template #trigger>
            <a-button type="primary" @click="handleDrawerTrigger">
              {{
                taskTypeMap[taskType]
              }}
            </a-button>
          </template>
          <template #content>
            <CveTask
              :task-type="taskType"
              :is-fixed="isCveFixed"
              :cve-list="cveList"
              :host-list-in-cve="hostListInCve"
              @cancel="tableState.isDrawerVisible = false"
              @close="tableState.isDrawerVisible = false"
              @success="
                tableState.isDrawerVisible = false;
                tableState.isSuccessModalVisible = true;
              "
            />
          </template>
        </CreateTaskDrawer>
      </a-col>
    </a-row>
    <a-table
      v-model:expandedRowKeys="tableState.expandedRowKeys"
      row-key="host_id"
      :columns="hostTableColumns"
      :data-source="hostTableData"
      :pagination="pagination"
      :loading="tableState.loading"
      :row-selection="{
        selectedRowKeys: tableState.selectedRowKeys,
        onSelect,
        onSelectAll,
      }"
      @expand="handleExpand"
      @change="handleTableChange"
    >
      <template #expandedRowRender="{ record }">
        <a-table
          :row-key="(inner:Rpm) => isCveFixed ? `${record.host_id}&${inner.installed_rpm}}` : `${record.host_id}&${inner.installed_rpm}-${inner.available_rpm}`"
          :columns="hostExpandTableColumns"
          :data-source="record.rpms"
          :loading="!record.rpms"
          :pagination="false"
          :row-selection="{
            selectedRowKeys: tableState.expandSelectedRowKeys,
            onChange: onExpandSelectedChange,
            getCheckboxProps: tableState.getCheckboxProps,
          }"
        />
      </template>
      <template #bodyCell="{ record, column }">
        <template v-if="column.dataIndex === 'host_name'">
          <router-link
            :to="{
              path: `/vulnerability/hosts/host-detail/${record.host_id}`,
              query: { host_name: record.host_name },
            }"
          >
            {{ record.host_name }}
          </router-link>
        </template>
        <template v-if="column.dataIndex === 'repo'">
          {{
            record.repo_id
              ? repos.find((item) => item.repo_id === record.repo_id)?.repo_name || '————'
              : '————'
          }}
        </template>
        <template v-if="column.dataIndex === 'last_scan'">
          {{
            record.last_scan
              ? dayjs(record.last_scan * 1000).format('YYYY-MM-DD HH:mm:ss')
              : t('vul.notScaned')
          }}
        </template>
      </template>
    </a-table>

    <TaskModal
      v-model:visible="tableState.isSuccessModalVisible"
      :title="`${TaskNameEnum[taskType]}`"
    />
  </div>
</template>
